package com.ruoyi.system.timing;

import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.enums.DetailStatusEnum;
import com.ruoyi.system.timing.callback.TimingCallback;
import com.ruoyi.system.timing.callback.impl.DefaultCallback;
import com.ruoyi.system.timing.entity.PoolDomain;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Objects;

/**
 * 任务定时池
 * @author : anxinr
 * @date : 2023/8/16 15:36
 */
@Slf4j
@Data
@Component
public class ScheduleTimingPool {

    /**任务链表*/
    private static final LinkedList<PoolDomain> TIME_LIST_POOL = new LinkedList<>() ;

    /**默认的回调方法*/
    private static final TimingCallback DEFAULT_CALLBACK = new DefaultCallback() ;

    /**任务开启状态*/
    private static boolean startPool = false ;

    /**
     * 开启定时回调任务池
     * @return boolean
     */
    public static boolean startTimingPool() {
        startPool = true ;
        new Thread(ScheduleTimingPool::openTimingPool).start();
        log.info("开启定时任务池");
        return true;
    }

    /**
     * 启动定时任务
     * 任务不支持跨天需求
     * 因为这是每日计划
     */
    private static void openTimingPool() {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        while (startPool){
            /**如果池中没有正在运行的任务，则关闭池*/
            if (ScheduleTimingPool.getTimingPoolRunningCount().equals(0)) {
                ScheduleTimingPool.closeTimingPool() ;
                log.info("当前没有任务要运行，关闭定时提醒任务!");
                continue ;
            }
            /**获取当前时间*/
            String nowDateTimeString = format.format(new Date());
            Date nowDateTime = null ;
            try {
                nowDateTime = format.parse(nowDateTimeString);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            /**获取链表任务池的迭代器*/
            Iterator<PoolDomain> iterator = TIME_LIST_POOL.iterator();
            while (iterator.hasNext()){
                PoolDomain timing = iterator.next();
                /**如果当前任务处于暂停(完成)状态，则把当前任务从任务链表中移除*/
                if (!DetailStatusEnum.DETAIL_STATUS_NORMAL.getCode().equals(timing.getStatus())) {
                    continue;
                }
                /**如果提醒测试达到上限，则不再执行该任务*/
                if (timing.getNoticeCountRecord() >= timing.getNoticeCount()) {
                    timing.setStatus(DetailStatusEnum.DETAIL_STATUS_STOP.getCode());
                    continue;
                }
                /**获取当前任务的起始时间*/
                Date startTime = null ;
                Date endTime = null ;
                try {
                    startTime = format.parse(timing.getStartTime()) ;
                    endTime = format.parse(timing.getEndTime()) ;
                } catch (ParseException e) {
                    e.printStackTrace();
                    continue;
                }
                assert startTime != null;
                assert nowDateTime != null;
                assert endTime != null;
                /**如果小于范围，则跳过*/
                if (startTime.getTime() >= nowDateTime.getTime()) {
                    timing.setWaiting(Boolean.TRUE) ;
                    continue ;
                }else {
                    /**如果在时间范围内，则判断是否到达频率*/
                    if (endTime.getTime() >= nowDateTime.getTime()) {
                        timing.setWaiting(Boolean.FALSE) ;
                        if (timing.complianceFrequency()) {
                            timing.callback();
                            timing.setNoticeCountRecord(timing.getNoticeCountRecord() + 1);
                        }else {
                            continue;
                        }
                    }
                    /**如果超过时间范围，则设置为暂停*/
                    if (endTime.getTime() <= nowDateTime.getTime()) {
                        timing.setStatus(DetailStatusEnum.DETAIL_STATUS_STOP.getCode());
                    }
                }
            }
            /**每分钟检测一次*/
            try {
                Thread.sleep(60000L);
            } catch (InterruptedException e) {
                log.info("定时任务池启动休眠出错,关闭定时任务池，异常为 -> {}" ,e.getMessage()) ;
                startPool = false ;
            }
        }
    }


    /**
     * 放入定时任务池中
     * @param data
     * @param startTime
     * @param endTime
     * @param callback
     * @return
     */
    public static PoolDomain putTask(Object data ,String name ,String startTime ,String endTime ,Integer status ,Integer frequency ,TimingCallback callback) {
        PoolDomain domain = new PoolDomain(data ,name ,startTime ,endTime ,status ,frequency ,callback);
        try {
            Field id = data.getClass().getDeclaredField("id");
            Field noticeCount = data.getClass().getDeclaredField("noticeCount");
            id.setAccessible(Boolean.TRUE);
            noticeCount.setAccessible(Boolean.TRUE);
            domain.setId(Long.valueOf(id.get(data).toString()));
            domain.setNoticeCount(Integer.valueOf(noticeCount.get(data).toString()));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            throw new ServiceException("数据主体不存在id,将无法回调任务完成事件！") ;
        }
        TIME_LIST_POOL.addLast(domain) ;
        return domain ;
    }

    /**
     * 放入定时任务池中
     * @param data
     * @param startTime
     * @param endTime
     * @return
     */
    public static PoolDomain putTask(Object data ,String name,String startTime ,String endTime ,Integer status ,Integer frequency) {
        return putTask(data ,name ,startTime ,endTime ,status ,frequency ,DEFAULT_CALLBACK) ;
    }

    /**
     * 获取正在运行的定时任务数量
     * @return TIME_LIST_POOL.size()
     */
    public static Integer getTimingPoolRunningCount() {
        return TIME_LIST_POOL.size() ;
    }

    /**
     * 获取任务池开启状态
     * @return startPool
     */
    public static boolean getPoolOpenStatus() {
        return startPool ;
    }

    /**
     * 关闭定时回调任务池
     * @return boolean
     */
    public static boolean closeTimingPool() {
        startPool = false ;
        try {
            ScheduleTimingPool.TIME_LIST_POOL.clear() ;
        }catch (Exception e){
            e.printStackTrace();
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    public static boolean completeTimingTask(Long id) {
        if (Objects.isNull(id)) {
            return false ;
        }
        for (PoolDomain domain : TIME_LIST_POOL) {
            if (id.equals(domain.getId())) {
                domain.setWaiting(Boolean.FALSE);
                domain.setStatus(DetailStatusEnum.DETAIL_STATUS_SUCCESS.getCode());
                return true ;
            }
        }
        return false ;
    }



}
